home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / FTPCLI.C < prev    next >
C/C++ Source or Header  |  1997-08-18  |  48KB  |  1,916 lines

  1. /* Internet FTP client (interactive user)
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. /* Mods by G1EMM and PA0GRI */
  5. /* modifications for encrypted password by ik1che 900419 */
  6. /* added "resume" and "rput" commands for interrupted file transfers
  7.  * by iw0cnb 15 Feb 92 */
  8.  
  9. /* VIEW command added by Simon G1FHY. Mod by Paul@wolf.demon.co.uk */
  10. #include "global.h"
  11. #include "commands.h"
  12. #include "files.h"
  13. #ifdef UNIX
  14. #include <sys/stat.h>
  15. #endif
  16. #include "mbuf.h"
  17. #include "session.h"
  18. #ifdef MSDOS
  19. #include "ctype.h"
  20. #else
  21. #include "socket.h"
  22. #endif
  23. #include "netuser.h"
  24. #ifdef LZW
  25. #include "lzw.h"
  26. #endif
  27.  
  28. #if !defined(_lint)
  29. static char rcsid[] OPTIONAL = "$Id: ftpcli.c,v 1.28 1997/08/19 01:19:22 root Exp root $";
  30. #endif
  31.  
  32. #define    FTPDIRBUF    256
  33.  
  34. #ifdef ALLSESSIONS
  35. static int compsub (struct ftpcli * ftp, char *localname, char *remotename);
  36. static int txlate (int argc, char *argv[], void *p, const char *substr, int parm);
  37. static int doascii (int argc, char *argv[], void *p);
  38. static int dobatch (int argc, char *argv[], void *p);
  39. static int dobinary (int argc, char *argv[], void *p);
  40. static int docompare (int argc, char *argv[], void *p);
  41. static int doftpcd (int argc, char *argv[], void *p);
  42. static int doftpcdup (int argc, char *argv[], void *p);
  43. static int doftpdel (int argc, char *argv[], void *p);
  44. static int doget (int argc, char *argv[], void *p);
  45. static int dohash (int argc, char *argv[], void *p);
  46. static int doverbose (int argc, char *argv[], void *p);
  47. static int dolist (int argc, char *argv[], void *p);
  48. static int dols (int argc, char *argv[], void *p);
  49. static int domd5 (int argc, char *argv[], void *p);
  50. #ifdef ALLSESSIONS
  51. static int doldir (int argc, char *argv[], void *p);
  52. #endif
  53. static int dolcd (int argc, char *argv[], void *p);
  54. static int dolmkdir (int argc, char *argv[], void *p);
  55. static int dolrename (int argc, char *argv[], void *p);
  56. static int dolrmdir (int argc, char *argv[], void *p);
  57. #ifdef LZW
  58. static int doftplzw (int argc, char *argv[], void *p);
  59. #endif
  60. static int domcompare (int argc, char *argv[], void *p);
  61. static int domkdir (int argc, char *argv[], void *p);
  62. static int domget (int argc, char *argv[], void *p);
  63. static int domput (int argc, char *argv[], void *p);
  64. static int doput (int argc, char *argv[], void *p);
  65. static int dopwd (int argc, char *argv[], void *p);
  66. static int doftphelp (int argc, char *argv[], void *p);
  67. static int doquit (int argc, char *argv[], void *p);
  68. static int dormdir (int argc, char *argv[], void *p);
  69. static int doftprename (int argc, char *argv[], void *p);
  70. static int doresume (int argc, char *argv[], void *p);
  71. static int dorput (int argc, char *argv[], void *p);
  72. static int dotype (int argc, char *argv[], void *p);
  73. static int doftpview (int argc, char *argv[], void *p);
  74. static int ftpgetline (struct session * sp, const char *prompt, char *buf, int n);
  75. static int getresp (struct ftpcli * ftp, int mincode);
  76. static int doftpupdate (int argc, char *argv[], void *p);
  77. static long getsub (struct ftpcli * ftp, const char *command, const char *remotename,
  78.                 char *localname);
  79. static long putsub (struct ftpcli * ftp, char *remotename, char *localname, int putr);
  80. static void sendport (int s, struct sockaddr_in * thesocket);
  81. static char *ftpcli_login (struct ftpcli * ftp, char *host);
  82. #ifdef LZW
  83. static int synclzw (register struct ftpcli * ftp);
  84. #endif
  85. #ifdef MSDOS
  86. extern void strrev (char *str);
  87. #endif
  88.  
  89. static char Notsess[] = "Not an FTP session!\n";
  90. static int Ftp_type = ASCII_TYPE;
  91. static int Ftp_logbsize = 8;
  92.  
  93. static struct cmds Ftpcmds[] =
  94. {
  95.     { "",        donothing,    0, 0, NULLCHAR },
  96.     { "?",        doftphelp,    0, 0, NULLCHAR },
  97.     { "append",    doput,        0, 2, "append <localfile> <remotefile>" },
  98.     { "ascii",    doascii,    0, 0, NULLCHAR },
  99.     { "batch",    dobatch,    0, 0, NULLCHAR },
  100.     { "binary",    dobinary,    0, 0, NULLCHAR },
  101.     { "bye",    doquit,        0, 0, NULLCHAR },
  102.     { "cd",        doftpcd,    0, 2, "cd <directory>" },
  103.     { "cdup",    doftpcdup,    0, 0, NULLCHAR },
  104.     { "compare",    docompare,    0, 2, "compare <remotefile> [<localfile>]" },
  105.     { "del",    doftpdel,    0, 2, "del <remotefile>" },
  106.     { "dir",    dolist,        0, 0, NULLCHAR },
  107.     { "exit",    doquit,        0, 0, NULLCHAR },
  108.     { "get",    doget,        0, 2, "get <remotefile> <localfile>" },
  109.     { "hash",    dohash,        0, 0, NULLCHAR },
  110.     { "help",    doftphelp,    0, 0, NULLCHAR },
  111.     { "lcd",    dolcd,        0, 1, NULLCHAR },
  112. #ifdef ALLSESSIONS
  113.     { "ldir",    doldir,        0, 1, NULLCHAR },
  114. #endif
  115.     { "list",    dolist,        0, 0, NULLCHAR },
  116.     { "lmkdir",    dolmkdir,    0, 2, "lmkdir <local Directory>" },
  117.     { "lrename",    dolrename,    0, 3, "lrename <oldname> <newname>" },
  118.     { "lrmdir",    dolrmdir,    0, 2, "lrmdir <local Directory>" },
  119.     { "ls",        dols,        0, 0, NULLCHAR },
  120. #ifdef LZW
  121.     { "lzw",    doftplzw,    0, 0, NULLCHAR },
  122. #endif
  123.     { "mcompare",    domcompare,    0, 2, "mcompare <file> [<file> ...]" },
  124.     { "md",        domkdir,    0, 2, "md <directory>" },
  125.     { "md5",    domd5,        0, 2, "md5 <file>" },
  126.     { "mget",    domget,        0, 2, "mget <file> [<file> ...]" },
  127.     { "mkdir",    domkdir,    0, 2, "mkdir <directory>" },
  128.     { "mput",    domput,        0, 2, "mput <file> [<file> ...]" },
  129.     { "nlist",    dols,        0, 0, NULLCHAR },
  130.     { "nlst",    dols,        0, 0, NULLCHAR },
  131.     { "put",    doput,        0, 2, "put <localfile> <remotefile>" },
  132.     { "pwd",    dopwd,        0, 0, NULLCHAR },
  133.     { "quit",    doquit,        0, 0, NULLCHAR },
  134.     { "rename",    doftprename,    0, 3, "rename <oldname> <newname>" },
  135.     { "resume",    doresume,    0, 2, "resume <remotefile> <localfile>" },
  136.     { "rmdir",    dormdir,    0, 2, "rmdir <directory>" },
  137.     { "rput",    dorput,        0, 2, "rput <localfile> <remotefile>" },
  138.     { "type",    dotype,        0, 0, NULLCHAR },
  139.     { "update",    doftpupdate,    0, 0, NULLCHAR },
  140.     { "verbose",    doverbose,    0, 0, NULLCHAR },
  141.     { "view",    doftpview,    0, 2, "view <remotefile>"},
  142.     { NULLCHAR,    NULLFP ((int, char **, void *)),
  143.                     0, 0, NULLCHAR }
  144. };
  145.  
  146.  
  147. int
  148. doftphelp (int argc, char *argv[], void *p OPTIONAL)
  149. {
  150.     dohelper ("FTP commands:\n", &Ftpcmds[1], NULLCHAR, (argv[0][0] == '?' && argc == 1) ? NULLCHAR : FTPHelp, (argc == 2) ? argv[1] : NULLCHAR);
  151.     return 0;
  152. }
  153.  
  154.  
  155. /* Handle top-level FTP command */
  156. int
  157. doftp (int argc, char *argv[], void *p OPTIONAL)
  158. {
  159. struct session *sp;
  160. struct ftpcli ftp;
  161. struct sockaddr_in fsocket;
  162. int resp, vsave;
  163. char *buf, *bufsav, *un;
  164. char const *cp;
  165. char prmt[40];
  166. #ifdef notyet
  167. char l[17];
  168. #endif
  169. int control;
  170. static FILE *fp1 = NULLFILE;
  171. struct cur_dirs dirs;
  172. int pauseonexit = 0;
  173.  
  174.     /*Make sure this comes from console - WG7J*/
  175.     if (Curproc->input != Command->input)
  176.         return 0;
  177.  
  178.     /* Allocate a session control block */
  179.     if ((sp = newsession (argv[1], FTP, 0)) == NULLSESSION) {
  180.         tputs (TooManySessions);
  181.         return 1;
  182.     }
  183.     memset ((char *) &ftp, 0, sizeof (ftp));
  184.     ftp.control = ftp.data = -1;
  185.     ftp.verbose = V_BYTE;    /* changed to ver 4 default - KO4KS */
  186.     ftp.type = (char) Ftp_type;
  187.     ftp.logbsize = Ftp_logbsize;
  188.  
  189.     sp->cb.ftp = &ftp;    /* Downward link */
  190.     ftp.session = sp;    /* Upward link */
  191.  
  192.     ftp.curdirs = &dirs;
  193.  
  194.     fsocket.sin_family = AF_INET;
  195.     fsocket.sin_port = IPPORT_FTP;
  196.  
  197.     tprintf ("Resolving %s... ", sp->name);
  198.     if ((fsocket.sin_addr.s_addr = resolve (sp->name)) == 0) {
  199.         tprintf (Badhost, sp->name);
  200.         (void) keywait (NULLCHAR, 1);
  201.         freesession (sp);
  202.         return 1;
  203.     }
  204.     /* Open the control connection */
  205.     if ((control = sp->s = ftp.control = socket (AF_INET, SOCK_STREAM, 0)) == -1) {
  206.         tputs (Nosock);
  207.         (void) keywait (NULLCHAR, 1);
  208.         freesession (sp);
  209.         return 1;
  210.     }
  211.     (void) sockmode (sp->s, SOCK_ASCII);
  212.     (void) setflush (sp->s, -1);    /* Flush output only when we call getresp() */
  213.     tprintf ("Trying %s...\n", psocket ((struct sockaddr *) &fsocket));
  214.     tprintf ("Local Directory - %s\n", init_dirs (&dirs));
  215.     if (connect (control, (char *) &fsocket, sizeof (fsocket)) == -1)
  216.         goto quit;
  217.     tprintf ("FTP session %u connected to %s\n", (unsigned) (sp - Sessions),
  218.          sp->name);
  219.  
  220.     /* Wait for greeting from server */
  221.     resp = getresp (&ftp, 200);
  222.  
  223.     if (resp >= 400)
  224.         goto quit;
  225.     if ((un = getenv ("LOGNAME")) == NULLCHAR)
  226.         un = getenv ("USER");
  227.     if (un != NULLCHAR)
  228.         sprintf (prmt, "Enter user name (%s): ", un);
  229.     else
  230.         sprintf (prmt, "Enter user name: ");
  231.     /* Now process responses and commands */
  232.     buf = mallocw (LINELEN);
  233.  
  234.     /*lint -esym(668, fp1) */
  235.     if (argc > 2)    {
  236.         if ((fp1 = fopen (argv[2], READ_TEXT)) == NULLFILE)
  237.             goto quit1;
  238.         if (argc > 3 && tolower (argv[3][0]) == 'p')
  239.             pauseonexit = 1;
  240.     } else
  241.         pauseonexit = 1;
  242.  
  243.     while (resp != -1) {
  244.         switch (resp) {
  245.             case 220:    /* Sign-on banner; prompt for and send USER command */
  246.                 if ((cp = ftpcli_login (&ftp, sp->name)) == NULLCHAR) {
  247.                     if (argc > 2) {
  248.                         if (fgets (buf, LINELEN, fp1) == NULLCHAR)
  249.                             goto quit1;
  250.                     } else if (ftpgetline (sp, prmt, buf, LINELEN) == -1) {
  251.                         resp = -1;
  252.                         continue;
  253.                     }
  254.                     /* Send the command only if the user response
  255.                          * was non-null
  256.                          */
  257.                     if (buf[0] != '\n') {
  258.                         usprintf (control, "USER %s", buf);
  259.                         resp = getresp (&ftp, 200);
  260.                     } else {
  261.                         if (un != NULLCHAR) {
  262.                             usprintf (control, "USER %s\n", un);
  263.                             resp = getresp (&ftp, 200);
  264.                         } else {
  265.                             tputs ("No username sent\n");
  266.                             resp = 200;    /* dummy */
  267.                         }
  268.                     }
  269.                 } else {
  270.                     usprintf (control, "USER %s\n", cp);
  271.                     free (cp);
  272.                     resp = getresp (&ftp, 200);
  273.                 }
  274.                 break;
  275.             case 331:
  276.                 if (ftp.password == NULLCHAR) {
  277.                     /* turn off echo */
  278.                     if (argc > 2) {
  279.                         if (fgets (buf, LINELEN, fp1) == NULLCHAR)
  280.                             goto quit1;
  281.                     } else {
  282.                         sp->ttystate.echo = 0;
  283.                         if (ftpgetline (sp, "Password: ", buf, LINELEN) == -1) {
  284.                             resp = -1;
  285.                             continue;
  286.                         }
  287.                         tputc ('\n');
  288.                         /* Turn echo back on */
  289.                         sp->ttystate.echo = 1;
  290.                     }
  291.                     /* Send the command only if the user response
  292.                          * was non-null
  293.                          */
  294.                     if (buf[0] != '\n') {
  295.                         usprintf (control, "PASS %s", buf);
  296.                         resp = getresp (&ftp, 200);
  297.                     } else {
  298.                         tputs ("Password must be provided.\nLogin failed.\n");
  299.                         resp = 200;    /* dummy */
  300.                     }
  301.                 } else {
  302.                     usprintf (control, "PASS %s\n", ftp.password);
  303.                     resp = getresp (&ftp, 200);
  304.                     free (ftp.password);
  305.                     ftp.password = NULLCHAR;    /* clean up */
  306.                 }
  307.                 break;
  308.             case 230:    /* Successful login */
  309.                 /* Find out what type of system we're talking to */
  310.                 tputs ("ftp> syst\n");
  311.                 usprintf (control, "SYST\n");
  312.                 resp = getresp (&ftp, 200);
  313.                 break;
  314.             case 215:    /* Response to SYST command */
  315.                 cp = strchr (ftp.line, ' ');
  316.                 if (cp != NULLCHAR && strnicmp (cp + 1, System, strlen (System)) == 0) {
  317.                     ftp.type = IMAGE_TYPE;
  318.                     tputs ("Defaulting to binary mode\n");
  319.                 }
  320.                 resp = 200;    /* dummy */
  321.                 break;
  322. #ifdef notyet
  323.             case 399:    /* Encrypted password login */
  324.                 if (ftp.password == NULLCHAR) {
  325.                     if (ftpgetline (sp, "Key ? --> ", buf, LINELEN) == -1) {
  326.                         resp = -1;
  327.                         continue;
  328.                     }
  329.                     /* Send the command only if the user response
  330.                          * was non-null
  331.                          */
  332.                     if (buf[0] != '\n') {
  333.                         cp = strchr (ftp.line, ':');
  334.                         cp += 2;
  335.                         /*
  336.                             epass(htol(cp),buf,l);
  337.                               */
  338.                         l[16] = '\0';
  339.                         free (ftp.line);
  340.                         ftp.line = NULLCHAR;
  341.                         usprintf (control, "PASS %s\n", l);
  342.                         resp = getresp (&ftp, 200);
  343.                     } else {
  344.                         tputs ("Password must be provided.\nLogin failed.\n");
  345.                         resp = 200;    /* dummy */
  346.                     }
  347.                 } else {
  348.                     cp = strchr (ftp.line, ':');
  349.                     cp += 2;
  350.                     /*
  351.                         epass(htol(cp),ftp.password,l);
  352.                         */
  353.                     l[16] = '\0';
  354.                     free (ftp.line);
  355.                     ftp.line = NULLCHAR;
  356.                     usprintf (control, "PASS %s\n", l);
  357.                     resp = getresp (&ftp, 200);
  358.                     free (ftp.password);
  359.                     ftp.password = NULLCHAR;    /* clean up */
  360.                 }
  361.                 break;
  362. #endif
  363.             default:    /* Test the control channel first */
  364.                 if (sockstate (control) == NULLCHAR) {
  365.                     resp = -1;
  366.                     break;
  367.                 }
  368.                 if (argc > 2) {
  369.                     if (fgets (buf, LINELEN, fp1) == NULLCHAR)
  370.                         goto quit1;
  371.                 } else if (ftpgetline (sp, "ftp> ", buf, LINELEN) == -1) {
  372.                     resp = -1;
  373.                     continue;
  374.                 }
  375.                 /* Copy because cmdparse modifies the original */
  376.                 bufsav = strdup (buf);
  377.                 if ((resp = cmdparse (Ftpcmds, buf, &ftp)) != -1) {
  378.                     /* Valid command, free buffer and get another */
  379.                     free (bufsav);
  380.                 } else {
  381.                     /* Not a local cmd, send to remote server */
  382.                     usputs (control, bufsav);
  383.                     free (bufsav);
  384.  
  385.                     /* Enable display of server response */
  386.                     vsave = ftp.verbose;
  387.                     ftp.verbose = V_NORMAL;
  388.                     resp = getresp (&ftp, 200);
  389.                     ftp.verbose = (int16) vsave;
  390.                 }
  391.         }
  392.     }
  393. quit1:    free (buf);
  394. quit:    cp = sockerr (control);
  395.     tprintf ("FTP session %u closed: %s\n", (unsigned) (sp - Sessions),
  396.          cp != NULLCHAR ? cp : "EOF");
  397.  
  398.     if (ftp.fp != NULLFILE && ftp.fp != stdout)
  399.         (void) fclose (ftp.fp);
  400.     if (ftp.data != -1)
  401.         close_s (ftp.data);
  402.     if (ftp.control != -1)
  403.         close_s (ftp.control);
  404.     if (pauseonexit)
  405.         (void) keywait (NULLCHAR, 1);
  406.     if (fp1 != NULLFILE)
  407.         (void) fclose (fp1);
  408.     if (ftp.session != NULLSESSION)
  409.         freesession (ftp.session);
  410.     free_dirs (&dirs);
  411.     return 0;
  412. }
  413.  
  414.  
  415. /* Control verbosity level */
  416. static int
  417. doverbose (int argc, char *argv[], void *p)
  418. {
  419. register struct ftpcli *ftp;
  420.  
  421.     if ((ftp = (struct ftpcli *) p) == NULLFTP)
  422.         return -1;
  423.     return setshort (&ftp->verbose, "Verbose", argc, argv);
  424. }
  425.  
  426.  
  427. /* Enable/disable command batching */
  428. static int
  429. dobatch (int argc, char *argv[], void *p)
  430. {
  431. register struct ftpcli *ftp;
  432.  
  433.     if ((ftp = (struct ftpcli *) p) == NULLFTP)
  434.         return -1;
  435.     return setbool (&ftp->batch, "Command batching", argc, argv);
  436. }
  437.  
  438.  
  439. /* Enable/disable update flag */
  440. static int
  441. doftpupdate (int argc, char *argv[], void *p)
  442. {
  443. register struct ftpcli *ftp;
  444.  
  445.     if ((ftp = (struct ftpcli *) p) == NULLFTP)
  446.         return -1;
  447.     return setbool (&ftp->update, "Update with MD5", argc, argv);
  448. }
  449.  
  450.  
  451. /* Set verbosity to high (convenience command) */
  452. static int
  453. dohash (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
  454. {
  455. register struct ftpcli *ftp;
  456.  
  457.     if ((ftp = (struct ftpcli *) p) == NULLFTP)
  458.         return -1;
  459.     tputs ("Hash Printing ");
  460.     if (ftp->verbose == V_HASH) {
  461.         ftp->verbose = V_HASH + 1;
  462.         tputs ("Off\n");
  463.     } else {
  464.         tputs ("On\n");
  465.         ftp->verbose = V_HASH;
  466.     }
  467.     return 0;
  468. }
  469.  
  470.  
  471. /* Close session */
  472. static int
  473. doquit (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
  474. {
  475. register struct ftpcli *ftp;
  476.  
  477.     ftp = (struct ftpcli *) p;
  478.     if (ftp == NULLFTP)
  479.         return -1;
  480.     usprintf (ftp->control, "QUIT\n");
  481.     (void) getresp (ftp, 200);    /* Get the closing message */
  482.     (void) getresp (ftp, 200);    /* Wait for the server to close */
  483.     /* prevent spurious retry caused by "error" return */
  484.     ftp->state = EXITING_STATE;
  485.     return -1;
  486. }
  487.  
  488.  
  489. #ifdef LZW
  490. static int
  491. synclzw (register struct ftpcli *ftp)
  492. {
  493. int retval;
  494.  
  495.     usprintf (ftp->control, "XLZW %d %d\n", Lzwbits, Lzwmode);
  496.     retval = getresp (ftp, 200);
  497.     if (retval >= 200 && retval < 300) {
  498.         ftp->lzwbits = Lzwbits;
  499.         ftp->lzwmode = Lzwmode;
  500.     }
  501.     return retval;
  502. }
  503.  
  504.  
  505. /* Toggle LZW compressed streams mode on */
  506. static int
  507. doftplzw (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
  508. {
  509. register struct ftpcli *ftp;
  510.  
  511.     ftp = (struct ftpcli *) p;
  512.     if (ftp == NULLFTP)
  513.         return -1;
  514.     ftp->lzw ^= 1;
  515.     tprintf ("200 Client LZW o%s\n", (ftp->lzw) ? "n" : "ff");
  516.     return (200);
  517. }
  518.  
  519. #endif
  520.  
  521.  
  522. /* Rename remote file */
  523. static int
  524. doftprename (int argc OPTIONAL, char *argv[], void *p)
  525. {
  526. register struct ftpcli *ftp;
  527. int retval;
  528.  
  529.     ftp = (struct ftpcli *) p;
  530.     if (ftp == NULLFTP)
  531.         return -1;
  532.     usprintf (ftp->control, "RNFR %s\n", argv[1]);
  533.     retval = getresp (ftp, 350);
  534.  
  535.     if (retval != 350)
  536.         return (retval);
  537.     usprintf (ftp->control, "RNTO %s\n", argv[2]);
  538.     return (getresp (ftp, 200));
  539. }
  540.  
  541.  
  542. /* Rename local file */
  543. static int
  544. dolrename (int argc OPTIONAL, char *argv[], void *p)
  545. {
  546. register struct ftpcli *ftp;
  547. char fname1[128];
  548. char fname2[128];
  549.  
  550.     ftp = (struct ftpcli *) p;
  551.     if (ftp == NULLFTP)
  552.         return -1;
  553.     strncpy (fname1, make_fname (ftp->curdirs->dir, argv[1]), 128);
  554.     strncpy (fname2, make_fname (ftp->curdirs->dir, argv[2]), 128);
  555.     if (rename (fname1, fname2) == -1)
  556.         tprintf ("Can't rename: %s\n", SYS_ERRLIST(errno));
  557.     else
  558.         tprintf ("Local file renamed to '%s'\n", fname2);
  559.     return 0;
  560.  
  561. }
  562.  
  563.  
  564. static int
  565. txlate (int argc OPTIONAL, char *argv[], void *p, const char *substr, int parm)
  566. {
  567. register struct ftpcli *ftp;
  568.  
  569.     ftp = (struct ftpcli *) p;
  570.     if (ftp == NULLFTP)
  571.         return -1;
  572.     usprintf (ftp->control, "%s %s\n", substr, (parm) ? argv[1] : "");
  573.     return getresp (ftp, 200);
  574. }
  575.  
  576.  
  577. /* Pass PWD to server - included here to allow cmd to be viewed in help list */
  578. static int
  579. dopwd (int argc, char *argv[], void *p)
  580. {
  581.     return (txlate (argc, argv, p, "PWD", 0));
  582. }
  583.  
  584.  
  585. /* Translate 'cd' to 'cwd' for convenience */
  586. static int
  587. doftpcd (int argc, char *argv[], void *p)
  588. {
  589.     if (argc == 1)
  590.         return (dopwd (argc, argv, p));
  591.     return (txlate (argc, argv, p, "CWD", 1));
  592. }
  593.  
  594.  
  595. /* Pass CDUP to server - included here to allow cmd to be viewed in help list */
  596. static int
  597. doftpcdup (int argc, char *argv[], void *p)
  598. {
  599.     return (txlate (argc, argv, p, "CDUP", 0));
  600. }
  601.  
  602.  
  603. /* Translate 'del' to 'dele' for convenience */
  604. static int
  605. doftpdel (int argc, char *argv[], void *p)
  606. {
  607.     return (txlate (argc, argv, p, "DELE", 1));
  608. }
  609.  
  610.  
  611. /* Translate 'mkdir' to 'xmkd' for convenience */
  612. static int
  613. domkdir (int argc, char *argv[], void *p)
  614. {
  615.     return (txlate (argc, argv, p, "XMKD", 1));
  616. }
  617.  
  618.  
  619. /* Translate 'rmdir' to 'xrmd' for convenience */
  620. static int
  621. dormdir (int argc, char *argv[], void *p)
  622. {
  623.     return (txlate (argc, argv, p, "XRMD", 1));
  624. }
  625.  
  626.  
  627. static int
  628. dobinary (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
  629. {
  630. char *args[2];
  631. char buf[2];
  632.  
  633.     strcpy (buf, "I");
  634.     args[1] = buf;
  635.     return dotype (2, args, p);
  636. }
  637.  
  638.  
  639. static int
  640. doascii (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
  641. {
  642. char *args[2];
  643. char buf[2];
  644.  
  645.     strcpy (buf, "A");
  646.     args[1] = buf;
  647.     return dotype (2, args, p);
  648. }
  649.  
  650.  
  651. /* Handle "type" command from user */
  652. static int
  653. dotype (int argc, char *argv[], void *p)
  654. {
  655. register struct ftpcli *ftp;
  656.  
  657.     ftp = (struct ftpcli *) p;
  658.     if (ftp == NULLFTP)
  659.         return -1;
  660.     if (argc < 2) {
  661.         switch (ftp->type) {
  662.             case IMAGE_TYPE:
  663.                 tputs ("Image\n");
  664.                 break;
  665.             case ASCII_TYPE:
  666.                 tputs ("Ascii\n");
  667.                 break;
  668.             case LOGICAL_TYPE:
  669.                 tprintf ("Logical bytesize %u\n", ftp->logbsize);
  670.                 break;
  671.             default:
  672.                 break;
  673.         }
  674.         return 0;
  675.     }
  676.     switch (*argv[1]) {
  677.         case 'i':
  678.         case 'I':
  679.         case 'b':
  680.         case 'B':
  681.             ftp->type = IMAGE_TYPE;
  682.             break;
  683.         case 'a':
  684.         case 'A':
  685.             ftp->type = ASCII_TYPE;
  686.             break;
  687.         case 'L':
  688.         case 'l':
  689.             ftp->type = LOGICAL_TYPE;
  690.             ftp->logbsize = atoi (argv[2]);
  691.             break;
  692.         default:
  693.             tprintf ("Invalid type %s\n", argv[1]);
  694.             return 1;
  695.     }
  696.     return 0;
  697. }
  698.  
  699.  
  700. /* Handle "ftype" command */
  701. int
  702. doftype (int argc, char *argv[], void *p OPTIONAL)
  703. {
  704.     if (argc < 2) {
  705.         tputs ("Ftp initial TYPE is ");
  706.         switch (Ftp_type) {
  707.             case IMAGE_TYPE:
  708.                 tputs ("Image\n");
  709.                 break;
  710.             case ASCII_TYPE:
  711.                 tputs ("Ascii\n");
  712.                 break;
  713.             case LOGICAL_TYPE:
  714.                 tprintf ("Logical bytesize %u\n", Ftp_logbsize);
  715.                 break;
  716.             default:
  717.                 break;
  718.         }
  719.         return 0;
  720.     }
  721.     switch (*argv[1]) {
  722.         case 'i':
  723.         case 'I':
  724.         case 'b':
  725.         case 'B':
  726.             Ftp_type = IMAGE_TYPE;
  727.             break;
  728.         case 'a':
  729.         case 'A':
  730.             Ftp_type = ASCII_TYPE;
  731.             break;
  732.         case 'L':
  733.         case 'l':
  734.             if (argc < 3)    {
  735.                 tprintf ("requires a bytesize parameter\nUsage: ftype logical <size>\n");
  736.                 return 1;
  737.             }
  738.             Ftp_type = LOGICAL_TYPE;
  739.             Ftp_logbsize = atoi (argv[2]);
  740.             break;
  741.         default:
  742.             tprintf ("Invalid type %s\n", argv[1]);
  743.             return 1;
  744.     }
  745.     return 0;
  746. }
  747.  
  748.  
  749. /* View added to jnos1.08 by Simon G1FHY _ mod by Paul@wolf.demon.co.uk */
  750. /* Start view transfer. Syntax: view <remote name> */
  751. static int
  752. doftpview (int argc OPTIONAL, char *argv[], void *p)
  753. {
  754. char *remotename;
  755. register struct ftpcli *ftp;
  756.  
  757.     ftp = (struct ftpcli *) p;
  758.     if (ftp == NULLFTP) {
  759.         tputs (Notsess);
  760.         return 1;
  761.     }
  762.     remotename = argv[1];
  763.  
  764.     (void) getsub (ftp, "RETR", remotename, NULLCHAR);
  765.     return 0;
  766. }
  767.  
  768.  
  769. /* Start receive transfer. Syntax: get <remote name> [<local name>] */
  770. static int
  771. doget (int argc, char *argv[], void *p)
  772. {
  773. char *remotename, *localname;
  774. register struct ftpcli *ftp;
  775.  
  776.     ftp = (struct ftpcli *) p;
  777.     if (ftp == NULLFTP) {
  778.         tputs (Notsess);
  779.         return 1;
  780.     }
  781.     remotename = argv[1];
  782.     if (argc < 3)
  783.         localname = remotename;
  784.     else
  785.         localname = argv[2];
  786.  
  787.     if (!ftp->update || compsub (ftp, localname, remotename) != 0)
  788.         (void) getsub (ftp, "RETR", remotename, localname);
  789.     return 0;
  790. }
  791.  
  792.  
  793. /* Get a collection of files */
  794. static int
  795. domget (int argc, char *argv[], void *p)
  796. {
  797. register struct ftpcli *ftp;
  798. FILE *files, *filel;
  799. char tmpname[80];
  800. char *buf, *local;
  801. #ifdef MSDOS
  802. char *c;
  803. #endif
  804. int i;
  805. #ifdef MSDOS
  806. int inlist;
  807. #endif
  808. long r;
  809.  
  810.     if ((ftp = (struct ftpcli *) p) == NULLFTP) {
  811.         tputs (Notsess);
  812.         return 1;
  813.     }
  814.     (void) tmpnam (tmpname);
  815.     buf = mallocw (FTPDIRBUF);
  816.     ftp->state = RECEIVING_STATE;
  817.     for (i = 1; i < argc; i++) {
  818.         if (argv[i][0] == '@') {
  819. #ifdef MSDOS
  820.             inlist = 1;
  821. #endif
  822.             if ((filel = fopen (make_fname (ftp->curdirs->dir, &argv[i][1]), "r")) == NULLFILE) {
  823.                 tprintf ("Can't open listfile: %s\n", &argv[i][1]);
  824.                 continue;
  825.             }
  826.             if ((files = fopen (tmpname, "w")) == NULLFILE) {
  827.                 tprintf ("Can't open tempfile: %s\n", tmpname);
  828.                 continue;
  829.             }
  830.             while (fgets (buf, FTPDIRBUF, filel) != NULLCHAR)
  831.                 fputs (buf, files);
  832.  
  833.             (void) fclose (files);
  834.             (void) fclose (filel);
  835.             if ((files = fopen (tmpname, "r")) == NULLFILE) {
  836.                 tprintf ("Can't open tempfile: %s\n", tmpname);
  837.                 continue;
  838.             }
  839.         } else {
  840. #ifdef MSDOS
  841.             inlist = 0;
  842. #endif
  843.             r = getsub (ftp, "NLST", argv[i], tmpname);
  844.             if (ftp->abort)
  845.                 break;    /* Aborted */
  846.             if (r == -1 || (files = fopen (tmpname, "r")) == NULLFILE) {
  847.                 tprintf ("Can't NLST %s\n", argv[i]);
  848.                 unlink (tmpname);
  849.                 continue;
  850.             }
  851.         }
  852.         /* The tmp file now contains a list of the remote files, so
  853.          * go get 'em. Break out if the user signals an abort.
  854.          */
  855.         while (fgets (buf, FTPDIRBUF, files) != NULLCHAR) {
  856.             rip (buf);
  857.             local = strdup (buf);
  858. #ifdef    MSDOS
  859.             if (inlist) {
  860.                 strrev (local);
  861.                 (void) strtok (local, "\\/[]<>,?#~()&%");
  862.                 strrev (local);
  863.             }
  864.             if ((c = strstr (local, ".")) != NULLCHAR) {
  865.                 c++;
  866.                 c = strtok (c, ".");    /* remove 2nd period if any*/
  867.             }
  868. #endif
  869.             if (!ftp->update || compsub (ftp, buf, buf) != 0)
  870.                 (void) getsub (ftp, "RETR", buf, local);
  871.             usflush (ftp->control);
  872.             free (local);
  873.             if (ftp->abort) {
  874.                 /* User abort */
  875.                 ftp->abort = 0;
  876.                 (void) fclose (files);
  877.                 unlink (tmpname);
  878.                 free (buf);
  879.                 ftp->state = COMMAND_STATE;
  880.                 return 1;
  881.             }
  882.         }
  883.         (void) fclose (files);
  884.         unlink (tmpname);
  885.     }
  886.     free (buf);
  887.     ftp->state = COMMAND_STATE;
  888.     ftp->abort = 0;
  889.     return 0;
  890. }
  891.  
  892.  
  893. /* Resume interrupted file transfer. Syntax: resume <remote name> [<local name>] */
  894. static int
  895. doresume (int argc, char *argv[], void *p)
  896. {
  897. char *remotename, *localname;
  898. register struct ftpcli *ftp;
  899.  
  900.     ftp = (struct ftpcli *) p;
  901.     if (ftp == NULLFTP) {
  902.         tputs (Notsess);
  903.         return 1;
  904.     }
  905.     remotename = argv[1];
  906.     if (argc < 3)
  907.         localname = remotename;
  908.     else
  909.         localname = argv[2];
  910.  
  911.     (void) getsub (ftp, "RSME", remotename, localname);
  912.     return 0;
  913. }
  914.  
  915. /* List remote directory. Syntax: dir <remote files> [<local name>] */
  916. static int
  917. dolist (int argc, char *argv[], void *p)
  918. {
  919. char *remotename, *localname;
  920. register struct ftpcli *ftp;
  921.  
  922.     ftp = (struct ftpcli *) p;
  923.     if (ftp == NULLFTP) {
  924.         tputs (Notsess);
  925.         return 1;
  926.     }
  927.     remotename = argv[1];
  928.     if (argc > 2)
  929.         localname = argv[2];
  930.     else
  931.         localname = NULLCHAR;
  932.  
  933.     (void) getsub (ftp, "LIST", remotename, localname);
  934.     return 0;
  935. }
  936.  
  937.  
  938. /* Remote directory list, short form. Syntax: ls <remote files> [<local name>] */
  939. static int
  940. dols (int argc, char *argv[], void *p)
  941. {
  942. char *remotename, *localname;
  943. register struct ftpcli *ftp;
  944.  
  945.     ftp = (struct ftpcli *) p;
  946.     if (ftp == NULLFTP) {
  947.         tputs (Notsess);
  948.         return 1;
  949.     }
  950.     remotename = argv[1];
  951.     if (argc > 2)
  952.         localname = argv[2];
  953.     else
  954.         localname = NULLCHAR;
  955.  
  956.     (void) getsub (ftp, "NLST", remotename, localname);
  957.     return 0;
  958. }
  959.  
  960.  
  961. static int
  962. domd5 (int argc OPTIONAL, char *argv[], void *p)
  963. {
  964. char *remotename;
  965. register struct ftpcli *ftp;
  966. int control;
  967. int resp;
  968. int typewait = 0;
  969.  
  970.     ftp = (struct ftpcli *) p;
  971.     if (ftp == NULLFTP) {
  972.         tputs (Notsess);
  973.         return 1;
  974.     }
  975.     control = ftp->control;
  976.     remotename = argv[1];
  977.     if (ftp->typesent != ftp->type) {
  978.         switch (ftp->type) {
  979.             case ASCII_TYPE:
  980.                 usprintf (control, "TYPE A\n");
  981.                 break;
  982.             case IMAGE_TYPE:
  983.                 usprintf (control, "TYPE I\n");
  984.                 break;
  985.             case LOGICAL_TYPE:
  986.                 usprintf (control, "TYPE L %d\n", ftp->logbsize);
  987.                 break;
  988.             default:
  989.                 break;
  990.         }
  991.         ftp->typesent = ftp->type;
  992.         if (!ftp->batch) {
  993.             resp = getresp (ftp, 200);
  994.             if (resp == -1 || resp > 299)
  995.                 goto failure;
  996.         } else
  997.             typewait = 1;
  998.  
  999.     }
  1000.     usprintf (control, "XMD5 %s\n", remotename);
  1001.     if (typewait)
  1002.         (void) getresp (ftp, 200);
  1003.     (void) getresp (ftp, 200);
  1004. failure:
  1005.     return 0;
  1006. }
  1007.  
  1008.  
  1009. static int
  1010. docompare (int argc, char *argv[], void *p)
  1011. {
  1012. char *remotename, *localname;
  1013. register struct ftpcli *ftp;
  1014.  
  1015.     ftp = (struct ftpcli *) p;
  1016.     if (ftp == NULLFTP) {
  1017.         tputs (Notsess);
  1018.         return 1;
  1019.     }
  1020.     remotename = argv[1];
  1021.     if (argc > 2)
  1022.         localname = argv[2];
  1023.     else
  1024.         localname = remotename;
  1025.  
  1026.     if (compsub (ftp, localname, remotename) == 0)
  1027.         tputs ("Same\n");
  1028.     else
  1029.         tputs ("Different\n");
  1030.     return 0;
  1031. }
  1032.  
  1033.  
  1034. /* Compare a collection of files */
  1035. static int
  1036. domcompare (int argc, char *argv[], void *p)
  1037. {
  1038. register struct ftpcli *ftp;
  1039. FILE *files;
  1040. char *buf;
  1041. int i;
  1042. long r;
  1043. char tmpname[80];
  1044.  
  1045.     if ((ftp = (struct ftpcli *) p) == NULLFTP) {
  1046.         tputs (Notsess);
  1047.         return 1;
  1048.     }
  1049.     (void) tmpnam (tmpname);
  1050.     buf = mallocw (FTPDIRBUF);
  1051.     ftp->state = RECEIVING_STATE;
  1052.     for (i = 1; i < argc; i++) {
  1053.         r = getsub (ftp, "NLST", argv[i], tmpname);
  1054.         if (ftp->abort)
  1055.             break;    /* Aborted */
  1056.         if (r == -1 || (files = fopen (tmpname, "r")) == NULLFILE) {
  1057.             tprintf ("Can't NLST %s\n", argv[i]);
  1058.             unlink (tmpname);
  1059.             continue;
  1060.         }
  1061.         /* The tmp file now contains a list of the remote files, so
  1062.          * go get 'em. Break out if the user signals an abort.
  1063.          */
  1064.         while (fgets (buf, FTPDIRBUF, files) != NULLCHAR) {
  1065.             rip (buf);
  1066.             if (compsub (ftp, buf, buf) == 0)
  1067.                 tprintf ("%s - Same\n", buf);
  1068.             else
  1069.                 tprintf ("%s - Different\n", buf);
  1070.  
  1071.             if (ftp->abort) {
  1072.                 /* User abort */
  1073.                 ftp->abort = 0;
  1074.                 (void) fclose (files);
  1075.                 unlink (tmpname);
  1076.                 free (buf);
  1077.                 ftp->state = COMMAND_STATE;
  1078.                 return 1;
  1079.             }
  1080.         }
  1081.         (void) fclose (files);
  1082.         unlink (tmpname);
  1083.     }
  1084.     free (buf);
  1085.     ftp->state = COMMAND_STATE;
  1086.     ftp->abort = 0;
  1087.     return 0;
  1088. }
  1089.  
  1090.  
  1091. /* Common subroutine to compare a local with a remote file
  1092.  * Return 1 if files are different, 0 if they are the same
  1093.  */
  1094. static int
  1095. compsub (struct ftpcli *ftp, char *localname, char *remotename)
  1096. {
  1097. char const *mode = NULLCHAR;
  1098. char *cp;
  1099. FILE *fp;
  1100. int control;
  1101. int resp, i;
  1102. int typewait = 0;
  1103. char remhash[16];
  1104. char lochash[16];
  1105.  
  1106.     control = ftp->control;
  1107.  
  1108.     switch (ftp->type) {
  1109.         case IMAGE_TYPE:
  1110.         case LOGICAL_TYPE:
  1111.             mode = READ_BINARY;
  1112.             break;
  1113.         case ASCII_TYPE:
  1114.         default:
  1115.             mode = READ_TEXT;
  1116.             break;
  1117.     }
  1118.     if ((fp = fopen (make_fname (ftp->curdirs->dir, localname), mode)) == NULLFILE) {
  1119.         tprintf ("Can't read local file %s\n", make_fname (ftp->curdirs->dir, localname));
  1120.         return 1;
  1121.     }
  1122.     if (ftp->typesent != ftp->type) {
  1123.         switch (ftp->type) {
  1124.             case ASCII_TYPE:
  1125.                 usprintf (control, "TYPE A\n");
  1126.                 break;
  1127.             case IMAGE_TYPE:
  1128.                 usprintf (control, "TYPE I\n");
  1129.                 break;
  1130.             case LOGICAL_TYPE:
  1131.                 usprintf (control, "TYPE L %d\n", ftp->logbsize);
  1132.                 break;
  1133.             default:
  1134.                 break;
  1135.         }
  1136.         ftp->typesent = ftp->type;
  1137.         if (!ftp->batch) {
  1138.             resp = getresp (ftp, 200);
  1139.             if (resp == -1 || resp > 299)
  1140.                 goto failure;
  1141.         } else
  1142.             typewait = 1;
  1143.     }
  1144.     usprintf (control, "XMD5 %s\n", remotename);
  1145.     /* Try to overlap the two MD5 operations */
  1146.     (void) md5hash (fp, lochash, ftp->type == ASCII_TYPE);
  1147.     (void) fclose (fp);
  1148.     if (typewait && (resp = getresp (ftp, 200)) > 299)
  1149.         goto failure;
  1150.     if ((resp = getresp (ftp, 200)) > 299) {
  1151.         if (resp == 500)
  1152.             ftp->update = 0;    /* XMD5 not supported */
  1153.         goto failure;
  1154.     }
  1155.     if ((cp = strchr (ftp->line, ' ')) == NULLCHAR) {
  1156.         tputs ("Error in response\n");
  1157.         goto failure;
  1158.     }
  1159.     /* Convert ascii/hex back to binary */
  1160.     (void) readhex (remhash, cp, sizeof (remhash));
  1161.     if (ftp->verbose > 1) {
  1162.         tputs ("Loc ");
  1163.         for (i = 0; i < (int) sizeof (lochash); i++)
  1164.             tprintf ("%02x", lochash[i] & 0xff);
  1165.         tprintf (" %s\n", make_fname (ftp->curdirs->dir, localname));
  1166.     }
  1167.     if (memcmp (lochash, remhash, sizeof (remhash)) == 0)
  1168.         return 0;
  1169.     else
  1170.         return 1;
  1171. failure:
  1172.     return 1;
  1173. }
  1174.  
  1175.  
  1176. /* Common code to LIST/NLST/RETR/RSME and mget
  1177.  * Returns number of bytes received if successful
  1178.  * Returns -1 on error
  1179.  */
  1180. static long
  1181. getsub (register struct ftpcli *ftp, const char *command, const char *remotename, char *localname)
  1182. {
  1183. unsigned long total;
  1184. FILE *fp;
  1185. int resp, i, control, savmode;
  1186. char const *mode;
  1187. struct sockaddr_in lsocket;
  1188. struct sockaddr_in lcsocket;
  1189. int32 startclk, rate;
  1190. int vsave;
  1191. int typewait = 0;
  1192. int prevstate;
  1193. unsigned long starting;
  1194.  
  1195.     if (ftp == NULLFTP)
  1196.         return -1;
  1197.     control = ftp->control;
  1198.     savmode = ftp->type;
  1199. #ifdef __GNUC__
  1200.     mode = 0;        /* semi-spurious warning */
  1201. #endif
  1202.  
  1203.     switch (ftp->type) {
  1204.         case IMAGE_TYPE:
  1205.         case LOGICAL_TYPE:
  1206.             if (strcmp (command, "RSME") == 0)
  1207.                 mode = APPEND_BINARY;
  1208.             else
  1209.                 mode = WRITE_BINARY;
  1210.             break;
  1211.         default:
  1212.         case ASCII_TYPE:
  1213.             if (strcmp (command, "RSME") == 0)
  1214.                 mode = APPEND_TEXT;
  1215.             else
  1216.                 mode = WRITE_TEXT;
  1217.             break;
  1218.     }
  1219.     /* Open the file */
  1220.     if (localname == NULLCHAR) {
  1221.         fp = NULLFILE;
  1222.     } else if ((fp = fopen (make_fname (ftp->curdirs->dir, localname), mode)) == NULLFILE) {
  1223.         tprintf ("Can't write %s: %s\n", localname, SYS_ERRLIST(errno));
  1224.         return -1;
  1225.     }
  1226.     /* Open the data connection */
  1227.     ftp->data = socket (AF_INET, SOCK_STREAM, 0);
  1228.     (void) listen (ftp->data, 0);    /* Accept only one connection */
  1229.     prevstate = ftp->state;
  1230.     ftp->state = RECEIVING_STATE;
  1231.  
  1232.     /* Send TYPE message, if necessary */
  1233.     if (strcmp (command, "LIST") == 0 || strcmp (command, "NLST") == 0) {
  1234.         /* Directory listings are always in ASCII */
  1235.         ftp->type = ASCII_TYPE;
  1236.     }
  1237.     if (ftp->typesent != ftp->type) {
  1238.         switch (ftp->type) {
  1239.             case ASCII_TYPE:
  1240.                 usprintf (control, "TYPE A\n");
  1241.                 break;
  1242.             case IMAGE_TYPE:
  1243.                 usprintf (control, "TYPE I\n");
  1244.                 break;
  1245.             case LOGICAL_TYPE:
  1246.                 usprintf (control, "TYPE L %d\n", ftp->logbsize);
  1247.                 break;
  1248.             default:
  1249.                 break;
  1250.         }
  1251.         ftp->typesent = ftp->type;
  1252.         if (!ftp->batch) {
  1253.             resp = getresp (ftp, 200);
  1254.             if (resp == -1 || resp > 299)
  1255.                 goto failure;
  1256.         } else
  1257.             typewait = 1;
  1258.     }
  1259.     /* Send the PORT message. Use the IP address
  1260.      * on the local end of our control connection.
  1261.      */
  1262.     i = SOCKSIZE;
  1263.     (void) getsockname (ftp->data, (char *) &lsocket, &i);    /* Get port number */
  1264.     if (!i)
  1265.         goto failure;
  1266.     i = SOCKSIZE;
  1267.     (void) getsockname (ftp->control, (char *) &lcsocket, &i);
  1268.     if (!i)
  1269.         goto failure;
  1270.     lsocket.sin_addr.s_addr = lcsocket.sin_addr.s_addr;
  1271.     sendport (control, &lsocket);
  1272.     if (!ftp->batch) {
  1273.         /* Get response to PORT command */
  1274.         resp = getresp (ftp, 200);
  1275.         if (resp == -1 || resp > 299)
  1276.             goto failure;
  1277.     }
  1278. #ifdef LZW
  1279.     if (ftp->lzw && ftp->type == ASCII_TYPE) {
  1280.         int retval = 200;
  1281.  
  1282.         retval = synclzw (ftp);
  1283.         if (retval >= 200 && retval < 300)
  1284.             lzwinit (ftp->data, ftp->lzwbits, ftp->lzwmode);
  1285.     }
  1286. #endif
  1287.  
  1288.     /* Generate the command to start the transfer */
  1289.     if (remotename != NULLCHAR)
  1290.         usprintf (control, "%s %s\n", command, remotename);
  1291.     else
  1292.         usprintf (control, "%s\n", command);
  1293.  
  1294.     if (ftp->batch) {
  1295.         /* Get response to TYPE command, if sent */
  1296.         if (typewait) {
  1297.             resp = getresp (ftp, 200);
  1298.             if (resp == -1 || resp > 299)
  1299.                 goto failure;
  1300.         }
  1301.         /* Get response to PORT command */
  1302.         resp = getresp (ftp, 200);
  1303.         if (resp == -1 || resp > 299)
  1304.             goto failure;
  1305.     }
  1306.     /* Get the intermediate "150" response */
  1307.     resp = getresp (ftp, 100);
  1308.     if (resp == -1 || resp >= 400)
  1309.         goto failure;
  1310.  
  1311.     /* Wait for the server to open the data connection */
  1312.     (void) accept (ftp->data, NULLCHAR, (int *) NULL);
  1313.     startclk = msclock ();
  1314.  
  1315.     /* If output is to the screen, temporarily disable hash marking */
  1316.     vsave = ftp->verbose;
  1317.     if (vsave >= V_HASH && fp == NULLFILE)
  1318.         ftp->verbose = V_NORMAL;
  1319.     if (strcmp (command, "RSME") == 0) {
  1320.         if ((starting = getsize (fp)) == (unsigned long) -1)
  1321.             starting = 0L;
  1322.         usprintf (control, "%lu %lu\n", starting, checksum (fp, (long) starting));
  1323.         usflush (control);
  1324.         if (fp != NULLFILE)
  1325.             fseek (fp, (long) starting, SEEK_SET);
  1326.     }
  1327.     total = (unsigned long) recvfile (fp, ftp->data, ftp->type, (ftp->verbose >= V_HASH) ? ftp->verbose : 0);
  1328.     /* Immediately close the data connection; some servers (e.g., TOPS-10)
  1329.      * wait for the data connection to close completely before returning
  1330.      * the completion message on the control channel
  1331.      */
  1332.     close_s (ftp->data);
  1333.     ftp->data = -1;
  1334.  
  1335. #ifdef    CPM
  1336.     if (fp != NULLFILE && ftp->type == ASCII_TYPE)
  1337.         putc (CTLZ, fp);
  1338. #endif
  1339.     if (fp != NULLFILE && fp != stdout)
  1340.         (void) fclose (fp);
  1341.     if (remotename == NULLCHAR)
  1342.         remotename = "";
  1343.     if (total == (unsigned long) -1) {
  1344.         tprintf ("%s %s: Error/abort during data transfer\n", command, remotename);
  1345.     } else if (ftp->verbose >= V_SHORT) {
  1346.         startclk = msclock () - startclk;
  1347.         rate = 0;
  1348.         if (startclk != 0) {    /* Avoid divide-by-zero */
  1349.             if (total < 4294967L) 
  1350.                 rate = (long) ((total * 1000) / (uint32) startclk);
  1351.              else         /* Avoid overflow */
  1352.                 rate = (long) (total / (uint32) (startclk / 1000));
  1353.         }
  1354.         tprintf ("%s %s: %lu bytes in %lu sec (%lu/sec)\n",
  1355.              command, remotename, total, startclk / 1000, rate);
  1356.     }
  1357.     /* Get the "Sent" message */
  1358.     (void) getresp (ftp, 200);
  1359.  
  1360.     ftp->state = (char) prevstate;
  1361.     ftp->verbose = (int16) vsave;
  1362.     ftp->type = (char) savmode;
  1363.     return ((long) total);
  1364.  
  1365. failure:
  1366.     /* Error, quit */
  1367.     if (fp != NULLFILE && fp != stdout)
  1368.         (void) fclose (fp);
  1369.     close_s (ftp->data);
  1370.     ftp->data = -1;
  1371.     ftp->state = (char) prevstate;
  1372.     ftp->type = (char) savmode;
  1373.     return -1;
  1374. }
  1375.  
  1376.  
  1377. /* Send a file. Syntax: put <local name> [<remote name>] */
  1378. static int
  1379. doput (int argc, char *argv[], void *p)
  1380. {
  1381. register struct ftpcli *ftp;
  1382. char *remotename, *localname;
  1383.  
  1384.     if ((ftp = (struct ftpcli *) p) == NULLFTP) {
  1385.         tputs (Notsess);
  1386.         return 1;
  1387.     }
  1388.     localname = argv[1];
  1389.     if (argc < 3)
  1390.         remotename = localname;
  1391.     else
  1392.         remotename = argv[2];
  1393.  
  1394.     if (!ftp->update || compsub (ftp, localname, remotename) != 0)
  1395.         (void) putsub (ftp, remotename, localname, (*argv[0] == 'a') ? 2 : 0);
  1396.     return 0;
  1397. }
  1398.  
  1399.  
  1400. /* Put a collection of files */
  1401. static int
  1402. domput (int argc, char *argv[], void *p)
  1403. {
  1404. register struct ftpcli *ftp;
  1405. FILE *files;
  1406. int i;
  1407. #if 0
  1408. int j;
  1409. #endif
  1410. char tmpname[80];
  1411. char *buf, *file;
  1412.  
  1413.     if ((ftp = (struct ftpcli *) p) == NULLFTP) {
  1414.         tputs (Notsess);
  1415.         return 1;
  1416.     }
  1417.     (void) tmpnam (tmpname);
  1418.     if ((files = fopen (tmpname, "w+")) == NULLFILE) {
  1419.         tputs ("Can't list local files\n");
  1420.         unlink (tmpname);
  1421.         return 1;
  1422.     }
  1423.     for (i = 1; i < argc; i++) {
  1424.         /* Use the path in the ftp client struct, since user may have done
  1425.              * a lcd command to change dir !
  1426.              */
  1427.         file = pathname (ftp->curdirs->dir, argv[i]);
  1428. #if 0                /* was #ifdef MSDOS */
  1429.         /* Shift everything back one byte, pathname returns with a leading '/'! */
  1430.         for (j = 1; j <= strlen (file); j++)
  1431.             file[j - 1] = file[j];
  1432. #endif
  1433.         (void) getdir (file, 0, files);
  1434.         free (file);
  1435.     }
  1436.  
  1437.     rewind (files);
  1438.     buf = mallocw (FTPDIRBUF);
  1439.     ftp->state = SENDING_STATE;
  1440.     while (fgets (buf, FTPDIRBUF, files) != NULLCHAR) {
  1441.         rip (buf);
  1442.         if (!ftp->update || compsub (ftp, buf, buf) != 0)
  1443.             (void) putsub (ftp, buf, buf, 0);
  1444.         if (ftp->abort)
  1445.             break;    /* User abort */
  1446.         usflush (ftp->control);
  1447.     }
  1448.     (void) fclose (files);
  1449.     unlink (tmpname);
  1450.     free (buf);
  1451.     ftp->state = COMMAND_STATE;
  1452.     ftp->abort = 0;
  1453.     return 0;
  1454. }
  1455.  
  1456.  
  1457. /* Put a file, appending data to it - iw0cnb */
  1458. static int
  1459. dorput (int argc, char *argv[], void *p)
  1460. {
  1461. register struct ftpcli *ftp;
  1462. char *remotename, *localname;
  1463.  
  1464.     if ((ftp = (struct ftpcli *) p) == NULLFTP) {
  1465.         tputs (Notsess);
  1466.         return 1;
  1467.     }
  1468.     localname = argv[1];
  1469.     if (argc < 3)
  1470.         remotename = localname;
  1471.     else
  1472.         remotename = argv[2];
  1473.  
  1474.     (void) putsub (ftp, remotename, localname, 1);
  1475.     return 0;
  1476. }
  1477.  
  1478.  
  1479. /* Common code to put, mput.
  1480.  * Returns number of bytes sent if successful
  1481.  * Returns -1 on error
  1482.  */
  1483. static long
  1484. putsub (ftp, remotename, localname, putr)
  1485. register struct ftpcli *ftp;
  1486. char *remotename, *localname;
  1487. int putr;            /* Flag: 0 if standard put, 1 if put with resume, if 2 append */
  1488. {
  1489. char const *mode;
  1490. int i, resp, control;
  1491. unsigned long total;
  1492. FILE *fp;
  1493. struct sockaddr_in lsocket, lcsocket;
  1494. int32 startclk, rate;
  1495. int typewait = 0;
  1496. int prevstate;
  1497. char *line;
  1498. unsigned long starting;
  1499. unsigned long check, local_check;
  1500.  
  1501.     control = ftp->control;
  1502.     if (ftp->type == IMAGE_TYPE)
  1503.         mode = READ_BINARY;
  1504.     else
  1505.         mode = READ_TEXT;
  1506.  
  1507.     /* Open the file */
  1508.     if ((fp = fopen (make_fname (ftp->curdirs->dir, localname), mode)) == NULLFILE) {
  1509.         tprintf ("Can't read %s: %s\n", localname, SYS_ERRLIST(errno));
  1510.         return -1;
  1511.     }
  1512.     if (ftp->type == ASCII_TYPE && isbinary (fp)) {
  1513.         tprintf ("Warning: type is ASCII and %s appears to be binary\n", localname);
  1514.     }
  1515.     /* Open the data connection */
  1516.     ftp->data = socket (AF_INET, SOCK_STREAM, 0);
  1517.     (void) listen (ftp->data, 0);
  1518.     prevstate = ftp->state;
  1519.     ftp->state = SENDING_STATE;
  1520.  
  1521.     /* Send TYPE message, if necessary */
  1522.     if (ftp->typesent != ftp->type) {
  1523.         switch (ftp->type) {
  1524.             case ASCII_TYPE:
  1525.                 usprintf (control, "TYPE A\n");
  1526.                 break;
  1527.             case IMAGE_TYPE:
  1528.                 usprintf (control, "TYPE I\n");
  1529.                 break;
  1530.             case LOGICAL_TYPE:
  1531.                 usprintf (control, "TYPE L %d\n", ftp->logbsize);
  1532.                 break;
  1533.             default:
  1534.                 break;
  1535.         }
  1536.         ftp->typesent = ftp->type;
  1537.  
  1538.         /* Get response to TYPE command */
  1539.         if (!ftp->batch) {
  1540.             resp = getresp (ftp, 200);
  1541.             if (resp == -1 || resp > 299) {
  1542.                 goto failure;
  1543.             }
  1544.         } else
  1545.             typewait = 1;
  1546.     }
  1547.     /* Send the PORT message. Use the IP address
  1548.      * on the local end of our control connection.
  1549.      */
  1550.     i = SOCKSIZE;
  1551.     (void) getsockname (ftp->data, (char *) &lsocket, &i);
  1552.     if (!i)
  1553.         goto failure;
  1554.     i = SOCKSIZE;
  1555.     (void) getsockname (ftp->control, (char *) &lcsocket, &i);
  1556.     if (!i)
  1557.         goto failure;
  1558.     lsocket.sin_addr.s_addr = lcsocket.sin_addr.s_addr;
  1559.     sendport (control, &lsocket);
  1560.     if (!ftp->batch) {
  1561.         /* Get response to PORT command */
  1562.         resp = getresp (ftp, 200);
  1563.         if (resp == -1 || resp > 299) {
  1564.             goto failure;
  1565.         }
  1566.     }
  1567. #ifdef LZW
  1568.     if (ftp->lzw && ftp->type == ASCII_TYPE) {
  1569.         int retval = 200;
  1570.  
  1571.         retval = synclzw (ftp);
  1572.         if (retval >= 200 && retval < 300)
  1573.             lzwinit (ftp->data, ftp->lzwbits, ftp->lzwmode);
  1574.     }
  1575. #endif
  1576.  
  1577.     /* Generate the command to start the transfer */
  1578.     if (putr == 1)
  1579.         usprintf (control, "RPUT %s\n", remotename);
  1580.     else if (putr == 2)
  1581.         usprintf (control, "APPE %s\n", remotename);
  1582.     else
  1583.         usprintf (control, "STOR %s\n", remotename);
  1584.  
  1585.     if (ftp->batch) {
  1586.         /* Get response to TYPE command, if sent */
  1587.         if (typewait) {
  1588.             resp = getresp (ftp, 200);
  1589.             if (resp == -1 || resp > 299) {
  1590.                 goto failure;
  1591.             }
  1592.         }
  1593.         /* Get response to PORT command */
  1594.         resp = getresp (ftp, 200);
  1595.         if (resp == -1 || resp > 299) {
  1596.             goto failure;
  1597.         }
  1598.     }
  1599.     /* Get the intermediate "150" response */
  1600.     resp = getresp (ftp, 100);
  1601.     if (resp == -1 || resp >= 400) {
  1602.         goto failure;
  1603.     }
  1604.     /* Wait for the data connection to open. Otherwise the first
  1605.      * block of data would go out with the SYN, and this may confuse
  1606.      * some other TCPs
  1607.      */
  1608.     (void) accept (ftp->data, NULLCHAR, (int *) NULL);
  1609.  
  1610.     startclk = msclock ();
  1611.  
  1612.     if (putr == 1) {    /* Wait for file offset and checksum */
  1613.         char *ctmp;
  1614.         line = mallocw (40);
  1615.         if (recvline (control, (unsigned char *) line, 40) == -1) {
  1616.             free (line);
  1617.             goto failure;
  1618.         }
  1619.         starting = (unsigned long) atol (line);
  1620.         ctmp = strchr (line, ' ');
  1621.         if (ctmp != NULLCHAR)
  1622.             check = (unsigned long) atol (ctmp);
  1623.         else
  1624.             check = 0;
  1625.         free (line);
  1626.         local_check = checksum (fp, (long) starting);
  1627.         if (ftp->verbose >= V_HASH)
  1628.             tprintf ("Remote checksum: %lu - Local checksum: %lu - Offset: %lu\n", check, local_check, starting);
  1629.         check -= local_check;
  1630.         if (check != 0) {
  1631.             tprintf ("Can't send %s: files are different\n", localname);
  1632.             (void) shutdown (ftp->data, 1);
  1633.             (void) getresp (ftp, 200);
  1634.             goto failure;
  1635.         }
  1636.     }
  1637.     total = (unsigned long) sendfile (fp, ftp->data, ftp->type, (ftp->verbose >= V_HASH) ? ftp->verbose : 0);
  1638.     close_s (ftp->data);
  1639.     ftp->data = -1;
  1640.     (void) fclose (fp);
  1641.  
  1642.     /* Wait for control channel ack before calculating transfer time;
  1643.      * this accounts for transmitted data in the pipe.
  1644.      */
  1645.     (void) getresp (ftp, 200);
  1646.  
  1647.     if (total == (unsigned long) -1) {
  1648.         tprintf ("STOR %s: Error/abort during data transfer\n", remotename);
  1649.     } else if (ftp->verbose >= V_SHORT) {
  1650.         startclk = msclock () - startclk;
  1651.         rate = 0;
  1652.         if (startclk != 0) {    /* Avoid divide-by-zero */
  1653.             if (total < 4294967L)
  1654.                 rate = (long) ((total * 1000) / (uint32) startclk);
  1655.             else         /* Avoid overflow */
  1656.                 rate = (long) (total / (uint32)(startclk / 1000));
  1657.         }
  1658.         tprintf ("STOR %s: %lu bytes in %lu sec (%lu/sec)\n",
  1659.              remotename, total, startclk / 1000, rate);
  1660.     }
  1661.     ftp->state = (char) prevstate;
  1662.     return ((long) total);
  1663.  
  1664. failure:
  1665.     /* Error, quit */
  1666.     (void) fclose (fp);
  1667.     close_s (ftp->data);
  1668.     ftp->data = -1;
  1669.     ftp->state = (char) prevstate;
  1670.     return -1;
  1671. }
  1672.  
  1673.  
  1674. /* Abort a GET or PUT operation in progress. Note: this will leave
  1675.  * the partial file on the local or remote system
  1676.  */
  1677. int
  1678. doabort (int argc, char *argv[], void *p)
  1679. {
  1680. register struct session *sp;
  1681. register struct ftpcli *ftp;
  1682.  
  1683.     sp = (struct session *) p;
  1684.     if (sp == NULLSESSION)
  1685.         return -1;
  1686.  
  1687.     /* Default is the current session, but it can be overridden with
  1688.      * an argument.
  1689.      */
  1690.     if (argc > 1)
  1691.         sp = sessptr (argv[1]);
  1692.  
  1693.     if (sp == NULLSESSION || sp->type != FTP) {
  1694.         tputs ("Not an active FTP session\n");
  1695.         return 1;
  1696.     }
  1697.     ftp = sp->cb.ftp;
  1698.     switch (ftp->state) {
  1699.         case COMMAND_STATE:
  1700.             tputs ("No active transfer\n");
  1701.             return 1;
  1702.         case SENDING_STATE:
  1703.             /* Send a premature EOF.
  1704.              * Unfortunately we can't just reset the connection
  1705.              * since the remote side might end up waiting forever
  1706.              * for us to send something.
  1707.              */
  1708.             (void) shutdown (ftp->data, 1);    /* Note fall-thru */
  1709.             ftp->abort = 1;
  1710.             break;
  1711.         case RECEIVING_STATE:
  1712.             /* Just blow away the receive socket */
  1713.             (void) shutdown (ftp->data, 2);    /* Note fall-thru */
  1714.             ftp->abort = 1;
  1715.             break;
  1716.         default:
  1717.             break;
  1718.     }
  1719.     return 0;
  1720. }
  1721.  
  1722.  
  1723. /* send PORT message */
  1724. static void
  1725. sendport (int s, struct sockaddr_in *thesocket)
  1726. {
  1727.     /* Send PORT a,a,a,a,p,p message */
  1728.     usprintf (s, "PORT %u,%u,%u,%u,%u,%u\n",
  1729.           hibyte (hiword (thesocket->sin_addr.s_addr)),
  1730.           lobyte (hiword (thesocket->sin_addr.s_addr)),
  1731.           hibyte (loword (thesocket->sin_addr.s_addr)),
  1732.           lobyte (loword (thesocket->sin_addr.s_addr)),
  1733.           hibyte (thesocket->sin_port),
  1734.           lobyte (thesocket->sin_port));
  1735. }
  1736.  
  1737.  
  1738. /* Wait for, read and display response from FTP server. Return the result code.
  1739.  */
  1740. static int
  1741. getresp (ftp, mincode)
  1742. struct ftpcli *ftp;
  1743. int mincode;            /* Keep reading until at least this code comes back */
  1744. {
  1745. int rval;
  1746.  
  1747.     usflush (ftp->control);
  1748.     for (;;) {
  1749.         /* Get line */
  1750.         if (recvline (ftp->control, (unsigned char *) ftp->line, LINELEN) == -1) {
  1751.             rval = -1;
  1752.             break;
  1753.         }
  1754.         rip (ftp->line);/* Remove cr/lf */
  1755.         rval = atoi (ftp->line);
  1756.         if (rval >= 400 || ftp->verbose >= V_NORMAL)
  1757.             tprintf ("%s\n", ftp->line);    /* Display to user */
  1758.  
  1759.         /* Messages with dashes are continued */
  1760.         if (ftp->line[3] != '-' && rval >= mincode)
  1761.             break;
  1762.     }
  1763.     return rval;
  1764. }
  1765.  
  1766.  
  1767. /* Issue a prompt and read a line from the user */
  1768. static int
  1769. ftpgetline (struct session *sp, const char *prompt, char *buf, int n)
  1770. {
  1771.     /* If there's something already there, don't issue prompt */
  1772.     if (socklen (sp->input, 0) == 0)
  1773.         tputs (prompt);
  1774.  
  1775.     usflush (sp->output);
  1776.     return recvline (sp->input, (unsigned char *) buf, (unsigned) n);
  1777. }
  1778.  
  1779.  
  1780. /* Attempt to log in the user whose name is in ftp->username and password
  1781.  * in pass
  1782.  */
  1783. static char *
  1784. ftpcli_login (struct ftpcli *ftp, char *host)
  1785. {
  1786. char buf[80], *cp = NULLCHAR, *cp1;
  1787. FILE *fp;
  1788.  
  1789.  
  1790.     if ((fp = fopen (Hostfile, "r")) == NULLFILE)
  1791.         return NULLCHAR;
  1792.  
  1793.     while ((void) fgets (buf, sizeof (buf), fp), !feof (fp)) {
  1794.         buf[strlen (buf) - 1] = '\0';    /* Nuke the newline */
  1795.         if (buf[0] == '#')
  1796.             continue;    /* Comment */
  1797.         if ((cp = strchr (buf, ' ')) == NULLCHAR)
  1798.             /* Bogus entry */
  1799.             continue;
  1800.         *cp++ = '\0';    /* Now points to user name */
  1801.         if (strcmp (host, buf) == 0)
  1802.             break;    /* Found host name */
  1803.     }
  1804.     if (feof (fp)) {
  1805.         /* User name not found in file */
  1806.         (void) fclose (fp);
  1807.         return NULLCHAR;
  1808.     }
  1809.     (void) fclose (fp);
  1810.     /* Look for space after user field in file */
  1811.     cp = skipwhite (cp);
  1812.     if ((cp1 = strpbrk (cp, " \t")) == NULLCHAR)
  1813.         /* if not there then we'll prompt */
  1814.         ftp->password = NULLCHAR;
  1815.     else
  1816.         *cp1++ = '\0';    /* Now points to password */
  1817.     cp1 = skipwhite (cp1);
  1818.     ftp->password = (strcmp (cp, "*")) ? strdup (cp1) : strdup ("anonymous");
  1819.     return strdup (cp);
  1820. }
  1821.  
  1822.  
  1823. int
  1824. dolcd (int argc, char *argv[], void *p)
  1825. {
  1826. register struct ftpcli *ftp;
  1827.  
  1828.     ftp = (struct ftpcli *) p;
  1829.     if (ftp == NULLFTP) {
  1830.         tputs (Notsess);
  1831.         return 1;
  1832.     }
  1833.     if (argc > 1) {
  1834.         if (!dir_ok (argv[1], ftp->curdirs)) {
  1835.             tprintf ("Invalid Drive/Directory - %s\n", argv[1]);
  1836.             return 1;
  1837.         }
  1838.     }
  1839.     tprintf ("Local Directory - %s\n", ftp->curdirs->dir);
  1840.     return 0;
  1841. }
  1842.  
  1843.  
  1844. #ifdef ALLSESSIONS
  1845. int
  1846. doldir (int argc, char *argv[], void *p)
  1847. {
  1848. register struct ftpcli *ftp;
  1849. char **margv;
  1850.  
  1851.     margv = (char **) callocw (2, sizeof (char *));
  1852.  
  1853.     ftp = (struct ftpcli *) p;
  1854.     if (ftp == NULLFTP) {
  1855.         tputs (Notsess);
  1856.         return 1;
  1857.     }
  1858.     tputc ('\n');
  1859.     if (argc == 1)
  1860.         margv[1] = strdup (ftp->curdirs->dir);
  1861.     else
  1862.         margv[1] = strdup (make_dir_path (argc, argv[1], ftp->curdirs->dir));
  1863.     (void) dodir (2, margv, p);
  1864.     free (margv[1]);
  1865.     free (margv);
  1866.     tputc ('\n');
  1867.     return 0;
  1868. }
  1869.  
  1870. #endif
  1871.  
  1872.  
  1873. int
  1874. dolmkdir (int argc OPTIONAL, char *argv[], void *p)
  1875. {
  1876. register struct ftpcli *ftp;
  1877. char *buf;
  1878.  
  1879.     ftp = (struct ftpcli *) p;
  1880.     if (ftp == NULLFTP) {
  1881.         tputs (Notsess);
  1882.         return 1;
  1883.     }
  1884.     /*    undosify(argv[1]);    done in make_fname    */
  1885.     buf = strdup (make_fname (ftp->curdirs->dir, argv[1]));
  1886.     if (mkdir (buf, 0777) == -1)
  1887.         tprintf ("Can't make %s: %s\n", buf, SYS_ERRLIST(errno));
  1888.     else
  1889.         tprintf ("Directory %s Created\n", buf);
  1890.     free (buf);
  1891.     return 0;
  1892. }
  1893.  
  1894.  
  1895. int
  1896. dolrmdir (int argc OPTIONAL, char *argv[], void *p)
  1897. {
  1898. register struct ftpcli *ftp;
  1899. char *buf;
  1900.  
  1901.     ftp = (struct ftpcli *) p;
  1902.     if (ftp == NULLFTP) {
  1903.         tputs (Notsess);
  1904.         return 1;
  1905.     }
  1906.     buf = strdup (make_fname (ftp->curdirs->dir, argv[1]));
  1907.     if (rmdir (buf) == -1)
  1908.         tprintf ("Can't remove %s: %s\n", buf, SYS_ERRLIST(errno));
  1909.     else
  1910.         tprintf ("Directory %s Removed\n", buf);
  1911.     free (buf);
  1912.     return 0;
  1913. }
  1914.  
  1915. #endif
  1916.